﻿//-------------------------------------------------------------------------------------------------
// <copyright file="YahooStockDataProvider.cs" company="Andrew Craig Keller">
//  Copyright (c) Andrew Craig Keller.  All rights reserved.
// </copyright>
//-------------------------------------------------------------------------------------------------

namespace StockQuoteServices
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Net;
    using StockQuoteServices.Contracts;

    /// <summary>
    /// Populates stock and price history data from the Yahoo Finance CSV service.
    /// </summary>
    internal class YahooStockDataProvider : IStockDataProvider
    {
        /// <summary>
        /// Gets a <see cref="Stock"/> object populated with basic data and the last traded price
        /// for the stock with the given ticker symbol.
        /// </summary>
        /// <param name="tickerSymbol">
        /// the ticker symbol of the stock for which data is to be retrieved
        /// </param>
        /// <returns>
        /// a <see cref="Stock"/> object populated with basic data and the last traded price for
        /// the stock with the given ticker symbol
        /// </returns>
        public Stock GetStockInfo(string tickerSymbol)
        {
            var url = new YahooStockDataUrl(tickerSymbol);
            Stock result = ReadFromYahooStockDataCsv(url);
            result.TickerSymbol = tickerSymbol;

            return result;
        }

        /// <summary>
        /// Gets a <see cref="Stock"/> object for the stock with the given ticker symbol with daily
        /// price history for the given date range.
        /// </summary>
        /// <param name="tickerSymbol">
        /// the ticker symbol of the stock for which data is to be retrieved
        /// </param>
        /// <param name="priceRangeStart">
        /// the starting date of the time period for which price history should be retrieved
        /// </param>
        /// <param name="priceRangeEnd">
        /// the ending date of the time period for which price history should be retrieved
        /// </param>
        /// <returns>
        /// an <see cref="IList{T}"/> of <see cref="Stock"/> objects populated with daily prices
        /// for the given date range
        /// </returns>
        public IList<StockHistoricalPrice> GetStockPriceHistory(
            string tickerSymbol,
            DateTime priceRangeStart,
            DateTime priceRangeEnd)
        {
            var url = new YahooHistoricalPricesUrl(tickerSymbol, priceRangeStart, priceRangeEnd);

            return ReadFromYahooHistoricalCsv(url);
        }

        /// <summary>
        /// Reads the Yahoo stock data CSV file at the given URL into a <see cref="Stock"/> object.
        /// </summary>
        /// <param name="url">
        /// the URL of the stock data CSV file to be read
        /// </param>
        /// <returns>
        /// a <see cref="Stock"/> object populated with data from the CSV file at the given URL
        /// </returns>
        private static Stock ReadFromYahooStockDataCsv(YahooStockDataUrl url)
        {
            using (WebClient httpClient = new WebClient())
            using (Stream csvStream = httpClient.OpenRead(url.ToString()))
            using (StreamReader csvReader = new StreamReader(csvStream))
            {
                string[] data = csvReader.ReadLine().Split(
                    new string[] {"\","},
                    StringSplitOptions.None);
                return new Stock()
                {
                    Name = data[0].Trim('"'),
                    LastPrice = Convert.ToDecimal(data[1])
                };
            }
        }

        /// <summary>
        /// Reads the Yahoo historical stock price CSV file at the given URL into an
        /// <see cref="IList{T}"/> of <see cref="StockHistoricalPrice"/> objects.
        /// </summary>
        /// <param name="url">
        /// The URL of the historical stock price CSV file to be read
        /// </param>
        /// <returns>
        /// An <see cref="IList{T}"/> containing <see cref="StockHistoricalPrice"/> objects for
        /// each period contained in the CSV file at the given URL
        /// </returns>
        private static IList<StockHistoricalPrice> ReadFromYahooHistoricalCsv(
            YahooHistoricalPricesUrl url)
        {
            var historicalPrices = new List<StockHistoricalPrice>();

            using (WebClient httpClient = new WebClient())
            using (Stream csvStream = httpClient.OpenRead(url.ToString()))
            using (StreamReader csvReader = new StreamReader(csvStream))
            {
                // skip the heading row
                csvReader.ReadLine();

                string line;
                while ((line = csvReader.ReadLine()) != null)
                {
                    string[] priceData = line.Split(',');

                    historicalPrices.Add(new StockHistoricalPrice()
                        {
                            Date = DateTime.Parse(priceData[0]),
                            Open = Convert.ToDecimal(priceData[1]),
                            High = Convert.ToDecimal(priceData[2]),
                            Low = Convert.ToDecimal(priceData[3]),
                            Close = Convert.ToDecimal(priceData[4]),
                            Volume = Convert.ToDouble(priceData[5]),
                            AdjustedClose = Convert.ToDecimal(priceData[6])
                        });
                }
            }
                
            return historicalPrices;
        }
    }
}
